package qy.jalgotrade.eventprof;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import it.unimi.dsi.fastutil.doubles.DoubleArrayList;

/**
 * Results from the profiler.
 * 
 * @author qy
 *
 */
public class Results {

	private int __lookBack;

	private int __lookForward;

	private List<DoubleArrayList> __values;

	private int __eventCount;

	/**
	 * 
	 * @param eventsDict
	 * @param lookBack
	 * @param lookForward
	 */
	public Results(Map<String, List<Event>> eventsDict, int lookBack, int lookForward) {

		assert lookBack > 0 && lookForward > 0;
		__lookBack = lookBack;
		__lookForward = lookForward;
		__values = new ArrayList<>();
		for (int i = 0; i < __lookBack + __lookForward + 1; i++) {
			__values.add(new DoubleArrayList());
		}
		// Process events.
		for (Map.Entry<String, List<Event>> e : eventsDict.entrySet()) {
			for (Event event : e.getValue()) {
				// Skip events which are on the boundary or for some reason are not complete.
				if (event.isComplete()) {
					__eventCount++;
					// Compute cumulative returns: (1 + R1)*(1 + R2)*...*(1 + Rn)
					// values = np.cumprod(event.getValues() + 1)
					double[] values = event.getValues().toDoubleArray();
					for (int i = 0; i < values.length; i++) {
						values[i] = values[i] + 1;
					}
					for (int i = 1; i < values.length; i++) {
						values[i] = values[i] * values[i - 1];
					}
					// Normalize everything to the time of the event
					// values = values / values[event.getLookBack()]
					for (int i = 0; i < values.length; i++) {
						values[i] = values[i] / values[event.getLookBack()];
					}
					for (int t = -event.getLookBack(); t < event.getLookForward() + 1; t++) {
						setValue(t, values[t + event.getLookBack()]);
					}
				}
			}
		}
	}

	/**
	 * 
	 * @param t
	 * @return
	 */
	private int __mapPos(int t) {

		assert t >= -1 * __lookBack && t <= __lookForward;
		return t + __lookBack;
	}

	/**
	 * 
	 * @param t
	 * @param value
	 */
	public void setValue(int t, double value) {

		if (Double.isNaN(value)) {
			throw new IllegalArgumentException("Invalid value at time " + t);
		}
		int pos = __mapPos(t);
		__values.get(pos).add(value);
	}

	/**
	 * 
	 * @param t
	 * @return
	 */
	public DoubleArrayList getValues(int t) {

		int pos = __mapPos(t);
		return __values.get(pos);
	}

	/**
	 * 
	 * @return
	 */
	public int getLookBack() {

		return __lookBack;
	}

	/**
	 * 
	 * @return
	 */
	public int getLookForward() {

		return __lookForward;
	}

	/**
	 * Returns the number of events occurred. Events that are on the boundary are skipped.
	 * 
	 * @return
	 */
	public int getEventCount() {

		return __eventCount;
	}
}
